from typing import List, Optional

from fastapi import APIRouter, HTTPException

from app.schemas.common import OperationResult
from app.schemas.dns import (
    DNSRecord,
    DNSRecordBatchDeleteRequest,
    DNSRecordCreate,
    DNSRecordIdentifier,
    DNSRecordListRequest,
    DNSRecordStatus,
    DNSRecordUpdate,
    DomainListRequest,
    DomainSummary,
)
from app.services.datastore import store

router = APIRouter()


from app.schemas.credentials import CredentialListRequest
from app.services.cloud_providers.factory import CloudProviderFactory

@router.post("/domain/list", response_model=List[DomainSummary])
def list_domains(payload: Optional[DomainListRequest] = None) -> List[DomainSummary]:
    if payload and payload.credential_id:
        try:
            _, access_key, secret_key = store.get_decrypted_credential(payload.credential_id)
            # We need to know the provider to create the client. 
            # get_decrypted_credential returns (provider, access_key, secret_key)
            provider_name = _
            client = CloudProviderFactory.create(provider_name, access_key, secret_key)
            # Cloud providers return List[DomainSummary]
            return client.list_domains()
        except KeyError:
             raise HTTPException(status_code=404, detail="Credential not found")
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    return store.list_domains(payload)


@router.post("/record/list", response_model=List[DNSRecord])
def list_records(payload: Optional[DNSRecordListRequest] = None) -> List[DNSRecord]:
    if payload and payload.credential_id:
        try:
            _, access_key, secret_key = store.get_decrypted_credential(payload.credential_id)
            provider_name = _
            client = CloudProviderFactory.create(provider_name, access_key, secret_key)
            return client.list_records(payload.domain)
        except KeyError:
             raise HTTPException(status_code=404, detail="Credential not found")
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))
            
    # Fallback to local store if no credential_id (though schema might enforce it if we made it mandatory, 
    # but here it is optional in ListRequest). 
    # If domain is provided but no credential, we might return local records.
    return store.list_dns_records(payload)


def _get_provider_client_by_id(credential_id: str) -> object:
    try:
        provider_name, access_key, secret_key = store.get_decrypted_credential(credential_id)
        return CloudProviderFactory.create(provider_name, access_key, secret_key), provider_name
    except KeyError:
        raise HTTPException(status_code=404, detail="Credential not found")


@router.post("/record/create", response_model=DNSRecord)
def create_record(payload: DNSRecordCreate) -> DNSRecord:
    client, provider_name = _get_provider_client_by_id(payload.credential_id)
    try:
        # Create on cloud
        cloud_record = client.create_record(payload)
        # Save to local DB using Cloud ID as _id
        # We inject provider name since it's removed from payload
        extra_data = {"id": cloud_record.id, "provider": provider_name}
        return store.create_dns_record(payload, extra_data=extra_data)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/record/update", response_model=DNSRecord)
def update_record(payload: DNSRecordUpdate) -> DNSRecord:
    try:
        current = store.get_dns_record(payload.id)
        client, _ = _get_provider_client_by_id(payload.credential_id)
        client.update_record(current.domain, payload)
        return store.update_dns_record(payload)
    except KeyError:
        raise HTTPException(status_code=404, detail="Record not found")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/record/delete", response_model=OperationResult)
def delete_record(payload: DNSRecordIdentifier) -> OperationResult:
    try:
        current = store.get_dns_record(payload.id)
        client, _ = _get_provider_client_by_id(payload.credential_id)
        client.delete_record(current.domain, payload)
        store.delete_dns_record(payload)
    except KeyError:
        raise HTTPException(status_code=404, detail="Record not found")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    return OperationResult(message="dns record deleted")


@router.post("/record/batch_delete", response_model=OperationResult)
def batch_delete_records(payload: DNSRecordBatchDeleteRequest) -> OperationResult:
    # We iterate and delete individually for safety and simplicity in this demo
    count = 0
    for rid in payload.ids:
        try:
            # Construct identifier with credential_id
            delete_record(DNSRecordIdentifier(id=rid, credential_id=payload.credential_id))
            count += 1
        except Exception:
            pass
    return OperationResult(message=f"deleted {count} records")


@router.post("/record/pause", response_model=DNSRecord)
def pause_record(payload: DNSRecordIdentifier) -> DNSRecord:
    try:
        current = store.get_dns_record(payload.id)
        client, _ = _get_provider_client_by_id(payload.credential_id)
        
        update_payload = DNSRecordUpdate(id=payload.id, credential_id=payload.credential_id, status=DNSRecordStatus.paused)
        client.update_record(current.domain, update_payload)
        
        return store.set_dns_record_status(payload.id, DNSRecordStatus.paused)
    except KeyError:
        raise HTTPException(status_code=404, detail="Record not found")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/record/resume", response_model=DNSRecord)
def resume_record(payload: DNSRecordIdentifier) -> DNSRecord:
    try:
        current = store.get_dns_record(payload.id)
        client, _ = _get_provider_client_by_id(payload.credential_id)
        
        update_payload = DNSRecordUpdate(id=payload.id, credential_id=payload.credential_id, status=DNSRecordStatus.active)
        client.update_record(current.domain, update_payload)
        
        return store.set_dns_record_status(payload.id, DNSRecordStatus.active)
    except KeyError:
        raise HTTPException(status_code=404, detail="Record not found")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
